/*
 Copyright (C) 2008  Maurizio Monticelli

 This program is free software; you can redistribute it and/or modify it under the terms of the 
 GNU General Public License as published by the Free Software Foundation; either version 2 of the 
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 
 Public License for more details.

 You should have received a copy of the GNU General Public License along with this program; if not, write 
 to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 
 */

package ch.justdoit.andriodrpncalc.model.command;

import java.util.Stack;

import org.lsmp.djep.groupJep.GroupJep;
import org.lsmp.djep.groupJep.groups.BigReals;
import org.lsmp.djep.groupJep.groups.Integers;
import org.lsmp.djep.groupJep.groups.Rationals;
import org.lsmp.djep.groupJep.groups.Reals;
import org.nfunk.jep.JEP;
import org.nfunk.jep.Node;

import ch.justdoit.andriodrpncalc.model.CalcNumber;
import ch.justdoit.andriodrpncalc.model.Model;
import ch.justdoit.andriodrpncalc.model.Settings;

public class EvaluateCommand extends BaseCommand {

	public EvaluateCommand(Model _model) {
		super(_model);
		mCommandName="eval";
		mExpression = "";

	}

	private CalcNumber numA;

	@Override
	public boolean canUndo() {
		return true;
	}

	@Override
	public boolean doit() {
		boolean result = false;
		resetErrorMessage();
		if (mModel.stack.size() >= 1) {
			numA = mModel.stack.PopNumber();
			if (numA.isExpression()) {
				CalcNumber number = new CalcNumber(mModel);

				// try with bigReals
				try {
					if (mModel.mSettings.getCalcType() == Settings.TYPE.BIGREALS) {
						JEP j = new GroupJep(new BigReals(3));
						Node node;
						node = j.parse(numA.getExpressionString());
						Object value = j.evaluate(node);

						Stack<String> tokens = new Stack<String>();
						for (int i = 0; i < value.toString().length(); i++)
						{
							
							tokens.add(value.toString().substring(i, i));
						}
						//number.setExpressionString(value.toString());
						mModel.stack.Put(number);
					} else if (mModel.mSettings.getCalcType() == Settings.TYPE.REALS) {
						if (false) {
							JEP j = new GroupJep(new Reals());
							Node node;
							node = j.parse(numA.getExpressionString());
							Object value = j.evaluate(node);
	
							number.parseNumber(value.toString());
							//number.setExpressionString(value.toString());
							mModel.stack.Put(number);
						} else {
							org.nfunk.jep.JEP myParser = new org.nfunk.jep.JEP();
							myParser.addStandardFunctions();
							myParser.addStandardConstants();

							myParser.parseExpression(numA.getExpressionString());
							Double evalResult = myParser.getValue();
							mModel.stack.Put(evalResult);
							
							// Alternative syntax
							//Node node1 = myParser.parse(numA.getExpressionString());
							//Object val1 = myParser.evaluate(node1);
							
							//System.out.println("Value: "+val1);
							
							
							//number.parseNumber(val1.toString());
							//mModel.stack.Put(number);
							


						}
					} else if (mModel.mSettings.getCalcType() == Settings.TYPE.INTEGER) {
						JEP j = new GroupJep(new Integers());
						Node node;
						node = j.parse(numA.getExpressionString());
						Object value = j.evaluate(node);

						number.parseNumber(value.toString());
						//number.setExpressionString(value.toString());
						mModel.stack.Put(number);
					} else if (mModel.mSettings.getCalcType() == Settings.TYPE.RATIONALS) {
						JEP j = new GroupJep(new Rationals());
						Node node;
						node = j.parse(numA.getExpressionString());
						Object value = j.evaluate(node);

						number.parseNumber(value.toString());
						//number.setExpressionString(value.toString());
						mModel.stack.Put(number);
					}
				} catch (Exception e) {
					mModel.stack.Put(numA);
					mModel.setErrorMessage("EVAL Error: ParseError");
				}
				result = true;
			} else {
				mModel.stack.Put(numA);
			}

		} else {
			mModel.setErrorMessage("EVAL Error: Too few arguments");
		}
		return result;
	}

	@Override
	public boolean undo() {
		boolean result = true;
		mModel.stack.Pop();
		mModel.stack.Put(numA);
		return result;
	}

	@Override
	public ICommand createNewInstance() {		
		return new EvaluateCommand(mModel);
	}

}
